#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>

#define NUM_ROWS 3
#define NUM_COLS 3
#define N 10
#define GET_STRING_BOOL(x) x?"true":"false"

// 将多维数组的第 i 列置为0
void make_arr_cols_zero(int a[NUM_ROWS][NUM_COLS], int i) {
    // 将p声明为指向长度为 NUM_COLS的整形数组的指针。
    // *p一定要使用括号，如果没有，则编译器认为p是指针数组，而不是指向数组的指针。
    int (*p)[NUM_COLS];
    // p++ 将p移到下一行的开始位置。
    for (p = a; p < &a[NUM_ROWS]; p++) {
//    for (p = &a[0]; p < &a[NUM_ROWS]; p++) {
        (*p)[i] = 0;
    }
}

void print_array(int a[NUM_ROWS][NUM_COLS]) {
    int *p;
    for(p = a[0]; p < a[0] + (NUM_ROWS * NUM_COLS); p++) {
//    for(p = a[0]; p < &a[NUM_ROWS - 1][NUM_COLS]; p++) {
        printf("%d ", *p);
    }
    printf("\n");
}

void print_array1(int a[N]) {
    int *p;
    for(p = a; p < a + N; p++) {
        printf("%d ", *p);
    }
    printf("\n");
}

void example1() {
    int a[] = {5, 15, 34, 54, 14, 2, 52, 72};
    int *p = &a[1], *q = &a[5];

    printf("*(p + 3) = %d\n", *(p + 3)); // 14
    printf("*(q - 3) = %d\n", *(q - 3)); // 34
    printf("q - p = %d\n", q - p); // 14
    printf("p < q = %d\n", p < q); // 真 这个应该是内存地址的值，按照排序来看的话，是q大些
    printf("*p < *q = %d\n", *p < *q); // 假
}

void example2() {
    int a[] = {5, 15, 34, 54, 78, 14, 2, 52, 72};
    int *low = a, *high = a + 7, * middle;
//    middle = (high + low) / 2; // 有问题，因为指针之间不能相加
    printf("(high - low) / 2 = %lld\n", (high - low) / 2);
    middle = low + (high - low) / 2;
    printf("middle is %d\n", *middle);
}

void example3() {
    int a[N] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int *p = &a[0], *q = &a[N - 1], temp;

    while (p < q) {
        temp = *p;
        *p++ = *q;
        *q-- = temp;
    }
    // print 10 9 8 7 6 5 4 3 2 1
    print_array1(a);
}

void example5() {
    int a[N] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int *p = a;
     // wrong
    printf("p == a[0]=%d\n", p == a[0]); // 假，p是指针,a[0]是int类型
    printf("p == &a[0]=%d\n", p == &a[0]); // 真
    printf("*p == a[0]=%d\n", *p == a[0]); // 真
    printf("p[0] == a[0]=%d\n", p[0] == a[0]); // 真，编译器会把 p[0] 看做 *(p+i)
}

int example6_sum_array(const int a[], int n)
{
    int *p, sum;
    sum = 0;
    for (p = a; p < a + n; p++) {
        sum += *p;
    }
    return sum;
}

bool search(const int a[], int n, int key) {
    const int *p = a;
    while(p < a + n) {
        if(*p++ == key) {
            return true;
        }
    }
    return false;
}

void example7() {
    int a[8] = {1, 2, 3, 4, 5, 6, 7, 8};
    int key = 3;
    printf("search 3 result:%s\n", GET_STRING_BOOL(search(a, 8, key)));
    key = 10;
    printf("search 10 result:%s\n", GET_STRING_BOOL(search(a, 8, key)));
}

void store_zeros(int a[], int n) {
    int *p = a;
    while(p < a + n) {
        *p++ = 0;
    }
}

void example8() {
    int a[8] = {1, 2, 3, 4, 5, 6, 7, 8};
    store_zeros(a, 8);
    int *p = a;
    while (p < a + 8) {
        printf("%d ", *p++);
    }
    printf("\n");
}

double inner_product(const double *a, const double *b, int n) {
    const double *end = a + n;
    double result = 0;
    while (a < end) {
        result += *a++ * *b++;
    }
    return result;
}

void example9() {
    double a[3] = {1, 3, 5};
    double b[3] = {2, 4, 6};// 2+12+30=44
    printf("inner_product result is %g\n", inner_product(a, b, 3));
}

int *find_largest(int a[], int n) {
    int *max = a;
    int *p = a + 1;
    while(p < a + n) {
        if(*p > *max) {
            max = p;
        }
        p++;
    }
    return max;
}

void example11() {
    int a[3] = {1, 7, 5};
    printf("largest is %d\n", *find_largest(a, 3));
}

void find_two_largest(const int *a, int n, int *largest,
                      int *second_largest) {
    int *p = a;
    while (p < a + n) {
        if (*p > *largest) {
            *largest = *p;
        } else if(*p > *second_largest) {
            *second_largest = *p;
        }
        p++;
    }
}

void example12() {
    int a[5] = {9, 8, 7, 6, 5};
//    int largest_v = 0, second_largest_v;
//    int *largest, *second_largest;
//    largest = &largest_v;
//    second_largest = &second_largest_v;
    int largest = 0, second_largest = 0;
    find_two_largest(a, 5, &largest, &second_largest);
//    printf("largest is %d, second_largest is %d\n", *largest, *second_largest);
    printf("largest is %d, second_largest is %d\n", largest, second_largest);

}
#define DAYS 7
#define HOURS 24
void gen_temperatures(int temperatures[DAYS][HOURS]) {
    srand(time(NULL));

    int *index = temperatures;
    int *first = index;
    // init data
    while(index < &temperatures[DAYS - 1][HOURS - 1]) {
        *index++ = rand() % 40;
    }
}

void print_temperature(int temperatures[DAYS][HOURS]) {
    int hour = 0;
    int *index = temperatures[0];
    while(index < &temperatures[DAYS - 1][HOURS]) {
        int cur = *index++;
        printf("%02d ", cur);
        if(hour == HOURS - 1) {
            printf("\n");
            hour = 0;
        } else {
            hour++;
        }
    }
}

void example14() {

    int temperatures[DAYS][HOURS];
    gen_temperatures(temperatures);

    int *index = temperatures[0];


    index = temperatures;
    int day = 0;
    while (index <= temperatures[DAYS - 1]) {
        bool exist = search(index, HOURS, 32);
        if(exist) {
            printf("The %d day exist key\n", day);
        }
        day++;
        index += HOURS;
    }
}

void example15() {
    int day = 3;
    int temperatures[DAYS][HOURS];
    gen_temperatures(temperatures);

    print_temperature(temperatures);

    int *index = temperatures[day];
    printf("The temperature on day %d was:\n", day);
    while (index < temperatures[day] + HOURS) {
        printf("%02d ", *index++);
    }
    printf("\n");
    printf("\n");
}

void example16() {
    int temperatures[DAYS][HOURS];
    gen_temperatures(temperatures);

    print_temperature(temperatures);

    int *p = temperatures[0];
    int day = 0;
    while(p <= temperatures[DAYS - 1]) {
        int *max = find_largest(p, HOURS);
        printf("The max temperature on day %d was %d degree.\n", day, *max);
        p += HOURS;
        day++;
    }
}

#define LEN 3
int sum_two_dimensional_array(const int a[][LEN], int n)
{
    int i, j, sum = 0;
    for (i = 0; i < n; i++)
        for (j = 0; j < LEN; j++)
            sum += a[i][j];
    return sum;
}

int sum_two_dimensional_array_point(const int a[][LEN], int n) {
    int *p = a;
    int sum = 0;
    while(p <= &a[n - 1][LEN - 1]) {
        sum += *p++;
    }
    return sum;
}

void example17() {
    int sum = sum_two_dimensional_array_point((int [2][3]){{1,2,3}, {1,2,3}}, 2);
    printf("sum is %d\n", sum);
}
//-- 编程题
#define PROGRAM1_MSG_MAX_LENGTH  200
void program1a() {
    char msg[PROGRAM1_MSG_MAX_LENGTH] = "";
    char c;
    int index = 0;
    printf("Enter a message: ");
    while ((c = getchar()) != '\n') {
        if(index >= PROGRAM1_MSG_MAX_LENGTH) {
            printf("ERR:out of length\n");
            break;
        }
        msg[index++] = c;
    }
    printf("Reversal is: ");
    for (int i = index - 1; i >= 0; --i) {
        printf("%c", msg[i]);
    }
    printf("\n");
}
// 用指针代替整数来跟踪数组中的当前位置。
void program1b() {
    char msg[PROGRAM1_MSG_MAX_LENGTH] = "";
    char c;
    char *p = msg;
    int index = 0;
    printf("Enter a message: ");
    while ((c = getchar()) != '\n') {
        if(index >= PROGRAM1_MSG_MAX_LENGTH) {
            printf("ERR:out of length\n");
            break;
        }
        *p++ = c;
        index++;
    }
    printf("Reversal is: ");
    while (p >= msg) {
        printf("%c", *p--);
    }
    printf("\n");
}
// 编写程序读一条消息，然后检查这条消息是否是回文
void check_palindrome(char msg[], int index) {
    int l = 0, r = index - 1;
    bool palindrome = true;
    while (l < r) {
        if(msg[l++] != msg[r--]) {
            palindrome = false;
            break;
        }
    }
    if (palindrome) {
        printf("Palindrome\n");
    } else {
        printf("Not a palindrome\n");
    }
}

void check_palindrome_point(char msg[], int index) {
    char *l = msg, *r = &msg[index - 1];
    bool palindrome = true;
    while (l < r) {
        if(*l++ != *r--) {
            palindrome = false;
            break;
        }
    }
    if (palindrome) {
        printf("Palindrome\n");
    } else {
        printf("Not a palindrome\n");
    }
}

// 不忽略大小写，忽略标点符号
void program2() {
    char msg[PROGRAM1_MSG_MAX_LENGTH];
    int index = 0;
    char c;
    printf("Enter a message:");
    while ((c = getchar()) != '\n') {
        if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
            msg[index++] = c;
        }
    }

    check_palindrome(msg, index);
}

void program2b() {
    char msg[PROGRAM1_MSG_MAX_LENGTH];
    int index = 0;
    char *p = msg;
    char c;
    printf("Enter a message:");
    while ((c = getchar()) != '\n') {
        if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
            *p++ = c;
            index++;
        }
    }

    check_palindrome_point(msg, index);
}
// @see chapter9/chapter9.c#reverse_sentence
void program5() {
    char sentence[100];
    char *p = sentence;

    printf("Enter a sentence: ");
    char ch;
    char endCh;
    int i = 0;

    while ((ch = getchar()) != '\n' && ch != EOF){
        if (ch == '.' || ch == '?' || ch == '!' ) {
            endCh = ch;
        } else {
            *p++ = ch;
            i++;
        }
    }

    char *end = p;
    printf("Reversal of sentence:");
    while (p >= sentence) {
        if (*p == ' ') {
            for(char *j = p + 1; j < end; j++) {
                printf("%c", *j);
            }
            printf(" ");
            end = p;
        } else if (p == &sentence[0]) {
            for(char *j = p; j < end; j++) {
                printf("%c", *j);
            }
        }
        p--;
    }

    printf("%c\n", endCh);
}

int main(void) {
    print_array((int[NUM_ROWS][NUM_COLS]) {{1, 2, 3},
                                           {3, 4, 5},
                                           {6, 7, 8}});
    int a[NUM_ROWS][NUM_COLS] = {{1, 2, 3},
                                 {3, 4, 5},
                                 {6, 7, 8}};
    make_arr_cols_zero(a, 0);
    print_array(a);

    example1();
    example2();
    example3();

    int a1[3] = {1, 2, 3};
    int *p = a1;
    printf("++*p=%d\n", ++*p);
    printf("--*p=%d\n", --*p);
    printf("*++p=%d\n", *++p);
    (*p)++;
    printf("before (*p)++,*p=%d\n", *p);
    printf("*p++=%d\n", *p++);
    printf("*p=%d\n", *p);
    print_array1(a1);
    example5();
    printf("example6_sum_array result is %d\n", example6_sum_array(a1, 3));
    example7();
    example8();
    example9();
    example11();
    example12();
    example14();
    example15();
    example16();
    example17();
//    program1a();
//    program1b();
//    program2();
//    program2b();
// 编程题3题和4题没必要写了，写的时候用的就是数组名，而不是取地址符
    program5();
}